"""
Redis连接工具类
用于测试中连接和操作Redis数据库
"""
import os
import redis
from typing import Optional
from utils.logger_util import logger


class RedisUtil:
    """Redis操作工具类"""
    
    def __init__(self, host: str = None, port: int = None, password: str = None, 
                 db: int = 0, decode_responses: bool = True):
        """
        初始化Redis连接
        
        Args:
            host: Redis主机地址，默认从环境变量获取
            port: Redis端口，默认从环境变量获取
            password: Redis密码，默认从环境变量获取
            db: Redis数据库编号，默认0
            decode_responses: 是否自动解码响应，默认True
        """
        self.log = logger.getlog()
        
        # 从环境变量获取配置，如果参数未提供
        self.host = host or os.getenv('REDIS_HOST', '127.0.0.1')
        self.port = port or int(os.getenv('REDIS_PORT', 6379))
        self.password = password or os.getenv('REDIS_PASSWORD')
        self.db = db
        self.decode_responses = decode_responses
        
        self.client = None
        self._connect()
    
    def _connect(self):
        """建立Redis连接"""
        try:
            self.client = redis.Redis(
                host=self.host,
                port=self.port,
                password=self.password,
                db=self.db,
                decode_responses=self.decode_responses,
                socket_connect_timeout=5,
                socket_timeout=5,
                retry_on_timeout=True
            )
            
            # 测试连接
            self.client.ping()
            self.log.info(f"Redis连接成功: {self.host}:{self.port}")
            
        except redis.ConnectionError as e:
            self.log.error(f"Redis连接失败: {e}")
            raise
        except Exception as e:
            self.log.error(f"Redis初始化异常: {e}")
            raise
    
    def get(self, key: str) -> Optional[str]:
        """
        获取键值
        
        Args:
            key: 键名
            
        Returns:
            str: 键值，不存在返回None
        """
        try:
            value = self.client.get(key)
            self.log.debug(f"Redis GET: {key} = {value}")
            return value
        except Exception as e:
            self.log.error(f"Redis GET失败: {key}, 错误: {e}")
            return None
    
    def set(self, key: str, value: str, ex: int = None) -> bool:
        """
        设置键值，支持过期时间
        
        Args:
            key: 键名
            value: 键值
            ex: 过期时间（秒），None表示不设置过期时间
            
        Returns:
            bool: 设置成功返回True，失败返回False
        """
        try:
            result = self.client.set(key, value, ex=ex)
            if ex:
                self.log.debug(f"Redis SET: {key} = {value}, 过期时间: {ex}秒")
            else:
                self.log.debug(f"Redis SET: {key} = {value}")
            return result
        except Exception as e:
            self.log.error(f"Redis SET失败: {key}, 错误: {e}")
            return False
    
    def ttl(self, key: str) -> int:
        """
        获取键的剩余过期时间
        
        Args:
            key: 键名
            
        Returns:
            int: 剩余过期时间（秒）
                 -2: 键不存在
                 -1: 键存在但没有设置过期时间
                 >0: 剩余过期时间（秒）
        """
        try:
            ttl_value = self.client.ttl(key)
            self.log.debug(f"Redis TTL: {key} = {ttl_value}秒")
            return ttl_value
        except Exception as e:
            self.log.error(f"Redis TTL查询失败: {key}, 错误: {e}")
            return -2
    
    def flushall(self) -> bool:
        """
        清空Redis中的所有键值对
        
        Returns:
            bool: 清空成功返回True，失败返回False
        """
        try:
            result = self.client.flushall()
            self.log.info("Redis所有键值对已清空")
            return result
        except Exception as e:
            self.log.error(f"Redis清空失败: {e}")
            return False
    
    def close(self):
        """关闭Redis连接"""
        try:
            if self.client:
                self.client.close()
                self.log.info("Redis连接已关闭")
        except Exception as e:
            self.log.error(f"关闭Redis连接失败: {e}")
    
    def __enter__(self):
        """上下文管理器入口"""
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """上下文管理器出口"""
        self.close()